### Структуры MarcRecord, MarcField и SubField

Библиографическеские записи ИРБИС64 в основном соответствуют стандарту [MARC](https://ru.wikipedia.org/wiki/MARC). Бегло рассмотрим этот стандарт, чтобы понять логику структур `MarcRecord`, `MarcField` и `SubField`.

Стандарт MARC (MAchine-Readable Cataloging) представляет собой цифровой формат для описания документов (таких как книги), каталогизируемых библиотеками. Стандарт создан американским ученым Генриеттой Аврам в 1960-х годах. К 1971 году формат MARC стал национальным стандартом США для распространения библиографических данных. Два года спустя он стал международным стандартом. В настоящее время  существует несколько версий MARC, наиболее распространенной из которых является MARC21, созданный в 1999 году в результате гармонизации форматов MARC США и Канады, а также UNIMARC. UNIMARC поддерживается Постоянным комитетом UNIMARC ИФЛА и широко используется в Европе. Российский стандарт RUSMARC является адаптацией UNIMARC.

Все стандарты семейства MARC одинаково определяют три аспекта библиографической записи: каждая запись состоит из служебных данных заголовка и некоторого количества полей. Различия между версиями MARC состоят в обозначения полей, структуру записи и фактическом содержимом самой записи.

Для российских библиотек нормативным является стандарт [RUSMARC](http://rusmarc.ru).

#### MarcRecord

> **БИБЛИОГРАФИЧЕСКАЯ ЗАПИСЬ** (Bibliographic Record) – элемент библиографической информации, фиксирующий в документальной форме сведения об информационном ресурсе – объекте записи, позволяющие его идентифицировать, раскрыть его состав и содержание в целях библиографического поиска. В состав библиографической записи входит библиографическое описание, дополняемое, по мере необходимости, заголовком, терминами индексирования (классификационными индексами и предметными рубриками), аннотацией (рефератом), шифром хранения, дополнительными точками доступа, сведениями о связи с другими библиографическими записями и другой дополнительной информацией о ресурсе, обеспечивающей доступ к нему, датой завершения обработки ресурса, сведениями служебного характера.
>
> *Стандарт RUSMARC*

Записи MARC обычно хранятся и передаются в виде двоичных файлов, обычно с несколькими записями MARC, объединенными в один файл. MARC использует стандарт ISO 2709 для определения структуры каждой записи. Сюда входит маркер, указывающий, где начинается и заканчивается каждая запись, а также набор символов в начале каждой записи, которые обеспечивают каталог для поиска полей и подполей внутри записи.

ИРБИС64 может импортировать/экспортировать записи в формате ISO 2709. Кроме прочего, он воспринимает заголовок библиографической записи, хранящийся в файле формата ISO 2709, но во внутреннем представлении ИРБИС64 никаких средств для работы с заголовком записи нет.

Каждый экземпляр структуры `MarcRecord` соответствует одной записи в базе данных ИРБИС и имеет следующие атрибуты: 

* **database** -- имя базы данных, из которой загружена данная запись. Для вновь созданных записей `None`. После отправки записи на сервер поле `database` выставляется автоматически.
* **mfn** -- порядковый номер записи в базе данных. Для вновь созданных записей 0. После отправки записи на сервер поле `mfn` выставляется автоматически. Диапазон значений для MFN: от 1 до 4294967295. Обратите внимание, при реорганизации базы данных MFN записи может измениться!
* **status** -- состояние записи: удалена, отсутствует и т. д. Для вновь созданных записей 0. После отправки записи на сервер поле `status` выставляется автоматически. Обратите внимание, при реорганизации базе данных логически удалённые записи могут пропасть из неё.
* **version** -- номер версии записи. Для вновь созданных записей 0. При каждой отправке записи на сервер поле `version` выставляется автоматически. Поле `version` используется сервером ИРБИС64 для отслеживания конфликтов одновременного обновления записей несколькими клиентами. Обратите внимание, при реорганизации базе данных её версия может измениться!
* **fields** -- запись содержит произвольное количество полей. Технически их может быть 0, но на практике это означает сбой системы.

Описание структуры `MarcRecord` в виде таблицы:

Поле структуры | Тип      | Назначение
---------------|----------|-----------
fields         | Vector    | Динамический массив указателей на поля.
database       | Buffer   | Имя базы данных. Для вновь созданных записей пустое.
data           | void*    | Произвольные пользовательские данные.
mfn            | am_mfn   | MFN.
status         | am_flag  | Статус записи.
version        | am_int32 | Версия записи.

С данной структорой работают следующие функции:

* MarcField\* **record_add** (MarcRecord \*record, am_uint32 tag, const char \*value)

* MarcRecord\* **record_clone** (MarcRecord \*target, const MarcRecord \*source)

* am_bool **record_decode_lines** (MarcRecord \*record, Vector \*lines)

* am_bool **record_encode** (const MarcRecord \*record, const char \*delimiter, Buffer \*buffer)

* Span **record_fm** (const MarcRecord \*record, am_uint32 tag, char code)

* am_bool **record_fma** (const MarcRecord \*record, Vector \*array, am_uint32 tag, char code)

* MarcField\* **record_get_field** (const MarcRecord \*record, am_uint32 tag, size_t occurrence)

#### MarcField

> **ПОЛЕ** (Field) – определенная строка символов, идентифицированная меткой, содержащая одно или более подполей. Поле – часть записи, соответствующая одной области библиографического описания, одной предметной рубрике, одному шифру хранения и т.д. Может содержать данные переменной длины (переменное поле) и фиксированной длины (фиксированное поле).
>
> **МЕТКА** (Tag) – совокупность трех цифровых символов, используемая для идентификации поля.
>
> *Стандарт RUSMARC*

Каждое поле в записи MARC предоставляет информацию об элементе библиографической записи, например об авторе, заглавии, издателе, выходных данных и т. д. Поскольку оно было впервые разработано в то время, когда вычислительная мощность была низкой, и драгоценное пространство, MARC использует простой трехзначный числовой код (от 001-999) для идентификации каждого поля в записи.

ИРБИС64 поддерживает метки в диапазоне от 1 до 2147483647 (на практике используется диапазон от 1 до 9999). Начиная с версии 2018, ИРБИС64 резервирует метку 2147483647 для поля GUID - уникального идентификатора записи. При попытке экспортировать записи с нестандартными метками в формат ISO 2709 могут возникнуть проблемы.

Поле записи состоит из следующих элементов:

* Два индикатора.
* Данные до первого разделителя. Стандарт RUSMARC не допускает данных до первого разделителя, все данные должны помещаться в подполях. Однако в ИРБИС64 такие данные используются довольно широко (примеры -- поля 300 (Общие примечания) и 610 (Ненормированные ключевые слова)).
* Подполя.

Хотя технически поле может содержать одновременно и данные до первого разделителя, и подполя, но на практике такая ситуация означает сбой.

> **ИНДИКАТОР** (Indicator) – цифровой или буквенный символ, связанный с переменным полем, представляющий дополнительную информацию о содержании поля, взаимосвязи между данным полем и другими полями в записи или об указаниях компьютеру оперировать данными определенным образом.
>
> *Стандарт RUSMARC*

Стандартом MARC у полей предусмотрены также два односимвольных индикатора, но ИРБИС64 их не поддерживает. Он может только импортировать/экспортировать записи в формате ISO 2709 и в процессе импорта конвертировать индикаторы в обычные подполя.

> **ФИКСИРОВАННОЕ ПОЛЕ** (Fixed Field) – поле данных фиксированной длины и в фиксированном формате.
>
> **ПЕРЕМЕННОЕ ПОЛЕ** (Variable Field) – поле данных переменной длины. Переменное поле может состоять из одного или более элементов данных или подполей. Длина полей в символах определяется количеством символов, необходимых для текстовых данных, индикаторов, идентификаторов подполей и разделителя поля.
>
> *Стандарт RUSMARC*

Стандарт MARC предусматривает т. наз. "фиксированные" поля с метками от 1 до 9 включительно, которые имеют строго фиксированную структуру. ИРБИС64 такие поля обрабатывает особым образом только в ситуации импорта/экспорта в формат ISO 2709, в остальном же он их трактует точно так же, как и прочие поля (которые стандарт называет полями переменной длины).

Порядок подполей в поле важен, т. к. на этот порядок завязана обработка т. наз. "вложенных полей".

Стандартом MARC предусмотрено, что внутри поля могут повторяться подполя с одинаковым кодом, однако, ИРБИС64 вслед за ISIS очень ограниченно поддерживает эту ситуацию (см. форматный выход `&umarci`).

Описание структуры `MarcField` в виде таблицы:

Поле структуры | Тип       | Назначение
---------------|-----------|-----------
value          | Buffer    | Данные до первого разделителя (может быть пустым).
subfields      | Vector     | Динамический массив указателей на подполя.
tag            | am_uint32 | Метка поля.

С данной структорой работают следующие функции:

* SubField\* **field_add** (MarcField \*field, char code, const char \*value)

* MarcField\* **field_clear** (MarcField \*field)

* MarcField\* **field_clone** (MarcField \*target, const MarcField \*source)

* MarcField\* **field_decode** (MarcField \*field, Span span)

* am_bool **field_empty** (const MarcField \*field)

* Vector\* **field_get_embedded_fields** (const MarcField \*field, Vector \*array)

* SubField\* **field_get_first_subfield** (const MarcField \*field, char code)

* Span **field_get_first_subfield_value** (const MarcField \*field, char code)

* MarcField\* **field_init** (MarcField \*field, am_uint32 tag)

* MarcField\* **field_insert_at** (MarcField \*field, size_t index, const SubField \*subfield)

* MarcField\* **field_remove_at** (MarcField \*field, size_t index)

* MarcField\* **field_remove_subfield** (MarcField \*field, char code)

* Buffer\* **field_to_string** (const MarcField \*field, Buffer \*buffer)

* am_bool **field_verify** (const MarcField \*field)

#### SubField

> **ПОДПОЛЕ** (Subfield) – определенная единица информации в пределах поля.
>
> **ЭЛЕМЕНТ ДАННЫХ** (Data Element) – наименьшая единица библиографической записи, подлежащая точной идентификации. В переменном поле элемент данных идентифицируется идентификатором подполя, с помощью которого образуется подполе. В маркере записи (Record Label), справочнике (Directory) и в подполях фиксированной длины элементы данных, состоящие из кодов, идентифицируются соответствующими позициями своих символов.
>
> **ИДЕНТИФИКАТОР ПОДПОЛЯ** (Subfield Identifier) или **КОД ПОДПОЛЯ** (Subfield code) – код, идентифицирующий отдельные подполя внутри переменного поля. Состоит из двух символов. Первый символ – разделитель (Delimiter), всегда один и тот же уникальный символ, установленный по ISO 2709, второй символ – код подполя (Subfield code), который может быть цифровым или буквенным.
>
> **ПОДПОЛЕ ФИКСИРОВАННОЙ ДЛИНЫ** (Fixed Length Subfield) – подполе постоянной длины, все случаи применения которого определены положениями формата. Подполе фиксированной длины может быть определено как содержащее один или более элементов данных. Подполя фиксированной длины могут присутствовать в фиксированных полях, например, поле 100, подполе `$a`, и в переменных полях, например, поле 200, подполе `$z`.
>
> *Стандарт RUSMARC*

В стандарте RUSMARC принято ссылаться на подполя `$a`, `$b` и т. д.  В документации ИРБИС64 принято обозначение `^a`, `^b` и т. д. Мы будем придерживаться последнего обозначения. 

Стандарт допускает лишь как правило алфавитно-цифровые код подполей `A-Z, 0-9`, но в ИРБИС64 бывают подполя с экзотическими кодами вроде `!`, `(` и др.

Стандарт не допускает пустого значения поля, но на практике в ИРБИС64 такие подполя могут встречаться (возникают при сбоях и при нарушении технологии).

Коды подполей не чувствительны к регистру. Как правило, ИРБИС64 приводит коды к верхнему регистру, но это не точно. :)

ИРБИС64 трактует код подполя `*` как "данные до первого разделителя либо значение первого по порядку подполя" (смотря по тому, что присутствует в записи).

Описание структуры `SubField` в виде таблицы:

Поле структуры  | Тип    | Назначение
----------------|--------|-----------
value           | Buffer | Значение подполя
code            | char   | Код подполя (один байт!)

С данной структорой работают следующие функции:

* SubField\* **subfield_clone** (SubField \*target, const SubField \*source) -- клонирование подполя.

* SubField\* **subfield_decode** (SubField \*subfield, Span span) -- декодирование текстового представления.

* am_bool **subfield_empty** (const SubField \*subfield) -- проверка, не пусто ли поле.

* SubField\* **subfield_init** (SubField \*subfield, char code, const char \*value) -- инициализация подполя.

* Buffer\* **subfield_to_string** (const SubField \*subfield, Buffer \*buffer) -- кодирование в текстовое представление.

* am_bool **subfield_verify** (const SubField \*subfield) -- верификация подполя.

[Предыдущая глава](chapter2.md) | [Следующая глава](chapter4.md)
